package com.zhukaiyuan.oauth2.sys.service.impl;


import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;

import com.zhukaiyuan.oauth2.sys.service.LoginService;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;

import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.util.HashMap;
import java.util.Map;

@Service
public class LoginServiceImpl implements LoginService {

    /**
     * TODO 用于临时存放所有 Refresh Token，实际情况应该放在 Redis 中
     */
    private static Map<String, String> refreshTokenMaps = new HashMap<>();


    @Value("${security.oauth2.client.access-token-uri}")
    private String accessTokenUri;

    @Value("${security.oauth2.client.client-id}")
    private String clientId;

    @Value("${security.oauth2.client.client-secret}")
    private String clientSecret;

//    @Autowired
//    private BCryptPasswordEncoder passwordEncoder;
//
//    @Autowired
//    private UserDetailsService userDetailsService;

    @Autowired
    private RestTemplate restTemplate;

    /**
     * 登录成功后仅返回 Token
     *
     * @param username {@code String} 账号
     * @param password {@code String} 密码
     * @return {@code Map<String, String>} key: token
     */
    @Override
    public Map<String, String> getToken(String username, String password) {


        Map<String, String> result = new HashMap<>();

        // 通过 HTTP 客户端请求登录接口
        Map<String, Object> authParam = getAuthParam();
        authParam.put("username", username);
        authParam.put("password", password);
        authParam.put("grant_type", "password");

        // 获取 access_token
        String strJson = HttpUtil.post(accessTokenUri, authParam);
        JSONObject jsonObject = JSONUtil.parseObj(strJson);
        String token = String.valueOf(jsonObject.get("access_token"));
        String refresh = String.valueOf(jsonObject.get("refresh_token"));
        if (StringUtils.isNotBlank(token) && StringUtils.isNotBlank(refresh)) {
            // 将 refresh_token 保存在服务端
            refreshTokenMaps.put(token, refresh);

            // 将 access_token 返回给客户端
            result.put("token", token);
            return result;
        }

        return null;
    }

    /**
     * 刷新 Token
     *
     * @param accessToken {@code String} 使用旧 Token 换新 Token
     * @return {@code Map<String, String>} 新 Token，key: token
     */
    @Override
    public Map<String, String> refresh(String accessToken) {
        Map<String, String> result = new HashMap<>();

        // Access Token 不存在直接返回 null
        String refreshToken = refreshTokenMaps.get(accessToken);
        if (StringUtils.isBlank(refreshToken)) {
            throw new RuntimeException("登录失败");
        }

        // 通过 HTTP 客户端请求登录接口
        Map<String, Object> authParam = getAuthParam();
        authParam.put("grant_type", "refresh_token");
        authParam.put("refresh_token", refreshToken);
        String strJson = HttpUtil.post(accessTokenUri, authParam);
        JSONObject jsonObject = JSONUtil.parseObj(strJson);
        String token = String.valueOf(jsonObject.get("access_token"));
        String refresh = String.valueOf(jsonObject.get("refresh_token"));
        if (StringUtils.isNotBlank(token) && StringUtils.isNotBlank(refresh)) {
            // 删除旧 Token
            refreshTokenMaps.remove(accessToken);

            // 将 refresh_token 保存在服务端
            refreshTokenMaps.put(token, refresh);

            // 将 access_token 返回给客户端
            result.put("token", token);
            return result;
        }

        return null;
    }


    /**
     * 用户登出
     */
    @Override
    public String logout(String token) {

        Map<String, Object> param = new HashMap<>();
        param.put("token", token);
        String res = HttpUtil.post("http://localhost:8080/sys/logout", param);
        if ("SUCCESS".equals(res)){
            refreshTokenMaps.remove(token);
        }
        return res;
    }

    // 私有方法 ------------------------------------------- Begin

    private Map<String, Object> getAuthParam() {
        Map<String, Object> param = new HashMap<>();
        param.put("client_id", clientId);
        param.put("client_secret", clientSecret);
        return param;
    }
}
